3 $deck = (1..52).to_a + ["A", "B"] # Unkeyed deck - Keystream Step 1
7 message = message.upcase.tr("^A-Z", "")
13 message += "X" while message.rindex(" ") != message.size - 6
16 key_stream = generate(message.count("^ "))
19 values = message.split("").map { |letter| letter[0] - ?A + 1 }
22 key_values = key_stream.split("").map { |letter| letter[0] - ?A + 1 }
25 values.each_with_index do |value, index|
27 values[index] = value + key_values[index]
28 values[index] -= 26 if values[index] > 26
32 message = (values.map { |number| (number - 1 + ?A).chr }).join("")
39 key_stream = generate(message.size)
42 values = message.split("").map { |letter| letter[0] - ?A + 1 }
45 key_values = key_stream.split("").map { |letter| letter[0] - ?A + 1 }
48 values.each_with_index do |value, index|
50 if value <= key_values[index]
51 values[index] = value + 26 - key_values[index]
53 values[index] = value - key_values[index]
58 message = (values.map { |number| (number - 1 + ?A).chr }).join("")
63 def generate(count) # Keystream Steps
66 until key_stream.size == count
70 $deck.insert(1, $deck.pop)
72 $deck.insert(a + 1, $deck.delete_at(a))
78 $deck.insert(2, $deck.pop)
80 $deck.insert(1, $deck.delete_at(b))
82 $deck.insert(b + 2, $deck.delete_at(b))
90 $deck = $deck.values_at((bottom + 1)..53, top..bottom, 0...top)
93 if $deck[53].kind_of? Integer
94 $deck = $deck.values_at($deck[53]..52, 0...$deck[53], 53)
98 if $deck[0].kind_of? Integer
99 if $deck[$deck[0]].kind_of? Integer
100 key_stream.push($deck[$deck[0]])
103 if $deck[53].kind_of? Integer
104 key_stream.push($deck[53])
109 key_stream.map! do |number|
111 (number - 26 - 1 + ?A).chr
113 (number - 1 + ?A).chr
116 key_stream = key_stream.join("")
118 while i < key_stream.size
119 key_stream[i, 0] = " "
125 # Mind reading interface
126 if ARGV.size == 1 and ARGV[0] =~ /^(?:[A-Z]{5} )*[A-Z]{5}$/
127 puts decrypt(ARGV[0])
129 puts encrypt(ARGV[0])
131 puts "Usage: solitaire.rb MESSAGE"